//
// Created by cychen on 2023/3/10.
//

#include <iostream>
#include <cstring>
#include <fstream>
#include "Controller.h"
#include "InConfig.h"
#include "Const.h"
#include "Error.h"
#include "API.h"
#include "ErrorCode.h"

int execCalculation(vector<string> wordList) {
    int len = (int) wordList.size();
    char *words[11000];
    vectorToCharArray_(wordList, words);
    InConfig *InConfig = InConfig::getInstance();
    char *result[20000];

    int ret;
    int r = checkInConfig();

    if (r != 0) {
        return r;
    }

    switch (InConfig->getState()) {
        case STATE_NUM: {
            ret = gen_chains_all(words, len, result);
            r = checkRingError(ret, result);
            printChains(result, ret);
            break;
        }
        case STATE_WORD_COUNT: {
            ret = gen_chain_word(words, len, result,
                                 int2char(InConfig->getHeadLimit()),
                                 int2char(InConfig->getTailLimit()),
                                 int2char(InConfig->getRejectLimit()),
                                 InConfig->isRing());
            r = checkRingError(ret, result);
            printChain(result, ret);
            break;
        }
        case STATE_CHAR_COUNT: {
            ret = gen_chain_char(words, len, result,
                                 int2char(InConfig->getHeadLimit()),
                                 int2char(InConfig->getTailLimit()),
                                 int2char(InConfig->getRejectLimit()),
                                 InConfig->isRing());
            r = checkRingError(ret, result);
            printChain(result, ret);
            break;
        }
        default:
            cout << "InConfig is empty" << endl;
            std::exit(0);
    }
    return r;
}

int printChains(char *chain[], int len) {
    int r = 0;
    std::ofstream outFile("./solution.txt");
    cout << len << endl;
    outFile << len << endl;
    if (len > 20000) {
        r = TOO_LONG_RESULT;
        outFile << "" << endl;
        return throwError(r, (NO_INFO));
    }
    for (int i = 0; i < len; ++i) {
        cout << chain[i] << endl;
        outFile << chain[i] << endl;
    }
    return r;
}

int printChain(char *chain[], int len) {
    int r = 0;
    std::ofstream outFile("./solution.txt");
//    cout << len << endl;
//    outFile << len << endl;
    if (len < 2) {
        return 0;
    } else if (len > 20000) {
        r = TOO_LONG_RESULT;
        outFile << "" << endl;
        return throwError(r, (NO_INFO));
    }
    for (int i = 0; i < len; ++i) {
        cout << chain[i] << endl;
        outFile << chain[i] << endl;
    }
    return r;
}

char int2char(int n) {
    if (n < 0 || n > 26) {
        return '+';
    } else {
        return (char) ('a' + n);
    }
}

int vectorToCharArray_(vector<string> &strings, char *result[]) {
    unsigned long long size = strings.size();

// Convert each string to char* pointer and store in char*[] array
    for (int i = 0; i < size; i++) {
        size_t length = strings[i].size() + 1;
        result[i] = (char *) std::malloc(length);
        if (result[i]) {
            strcpy(result[i], strings[i].c_str());
        }
    }
    return 0;
}

int setInConfig(int _state, int _head, int _tail, int _reject, bool _ring, string &_filePath) {
    InConfig::resetInstance();
    InConfig *InConfig = InConfig::getInstance();
    if (_state != -1) {
        InConfig->setState(_state);
    }
    if (_head != -1) {
        InConfig->setHeadLimit(_head);
    }
    if (_tail != -1) {
        InConfig->setTailLimit(_tail);
    }
    if (_reject != -1) {
        InConfig->setRejectLimit(_reject);
    }
    InConfig->setRing(_ring);
    if (_filePath.length() > 0) {
        InConfig->setFilePath(_filePath);
    }
    return 0;
}

int checkRingError(int ret, char *result[]) {
    if (ret == 0 && result[0] != nullptr) {
        cout << "[Error -9]: Not exist '-r' parameter." << endl;
        return NOT_EXIST_RING_PARA;
    }
    return 0;
}


